# -*- coding:utf8 -*-
import json
import traceback
import os
import typing
import base64
from datetime import datetime, timedelta
from scrapy import Request, FormRequest
from squirrel_core.commons.utils.tools import calc_str_md5, upload_file
from squirrel_core.frame.spider_makaka import MakakaSpider

file_path = os.environ.get("FILE_PATH", "/")


class saike_score(MakakaSpider):
    name = "saike_score"
    serialNumber = ""
    home_url = "https://timerbackend.geexek.com/getCmpt.do"
    rank_url = "https://timerbackend.geexek.com/initNewList.do"
    base_score_url = "https://timerbackend.geexek.com/rankingBoard.do"
    detail_url = "https://timerbackend.geexek.com/getScoreInfo.do"
    extend_url = "https://timerbackend.geexek.com/getScoreInfo_extend.do"

    header = {
        "Host": "timerbackend.geexek.com",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
        "Accept": "*/*",
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "Origin": "https://www.geexek.com",
        "Referer": "https://www.geexek.com/",
        "Accept-Encoding": "gzip, deflate, br, zstd",
        "Accept-Language": "zh-CN,zh;q=0.9"
    }
    cmpt_id_dict = {
        "2025若尔盖国家公园天边小路越野赛": "29469",
        "蒙泰·2025鄂尔多斯马拉松": "29507",
        "2025凯乐石东北100松花湖跑山赛": "29528",
        "2025九月凯乐石FUGA训练赛南京站": "29613",
        "2025“赛动黔景”贵州·毕节赫章阿西里西登山、越野双日赛": "29700",
        "2025麒麟小勇士障碍挑战赛·秋季赛": "29779",
        "2025凯乐石贡嘎100冰川极限挑战赛": "29654",
        "2025MaXi-RaceChina江山100越野赛": "30045",
        "2025UTO助力首百汤山越野赛": "30155",
        "2025四川省“最美绿道”系列赛阆中古城站": "29946",
        "2025凯乐石莫干山跑山赛": "29775",
        "2025中江半程马拉松": "30089",
        "2025南充嘉陵江马拉松": "30188",
        "2025NORTHLAND阳朔100国际徒步越野赛": "30317",
        "2025重庆垫江明月山越野赛": "30322",
        "2025重庆江津东方爱情马拉松": "30239",
        "2025户外特工西宏168·寻秋徽州山径探索": "30518",
        "2025上海长滩半程马拉松": "30136",
        "2025广东从化一百超级越野赛": "29494",
        "第十届戴村山地越野赛": "30476"
    }

    def get_ext_requests_or_urls(self, data=None):
        if data and isinstance(data, str):
            data = json.loads(data)
        if data and isinstance(data, typing.MutableMapping):
            self.serialNumber = data.get("serialNumber", "")
            race_id = data.get("spider_config", {}).get("race_id", "")
            user_id = data.get("spider_config", {}).get("user_id", "")
            race_no = data.get("spider_config", {}).get("race_no", "")
            user_name = data.get("spider_config", {}).get("user_name", "")
            card_num = data.get("spider_config", {}).get("card_num", "")
            race_name = data.get("spider_config", {}).get("race_name", "").replace(" ", "")
            if not user_name and not race_no:
                self.logger.info("user_name和race_no必须存在一个")
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 101, "message": "user_name和race_no必须存在一个"})
                self.close_after_idle = True
                self.force_to_close_spider = True
            else:
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 100, "message": "任务启动成功"})
                keyword = race_no or user_name
                if race_name in ["2025凯乐石贡嘎100冰川极限挑战赛", "2025四川省“最美绿道”系列赛阆中古城站", "2025上海长滩半程马拉松"]:
                    keyword = card_num
                    self.home_url = "https://timerbackend.geexek.com/getCmptforSingle.do?isSingleRank=1&queryType=0011&markNo="
                r_name = race_name
                if "FUGA训练赛" in race_name and "南京站" in race_name and "九月" in race_name:
                    r_name = "2025九月凯乐石FUGA训练赛南京站"
                cmptId = self.cmpt_id_dict.get(r_name, "")
                post_data = {"cmptId": cmptId, "keyword": keyword}
                yield FormRequest(url=self.home_url, callback=self.parse, formdata=post_data, dont_filter=True, errback=self.err_parse, headers=self.header,
                                  meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name, "post_data": post_data})

    def parse(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        race_name = response.meta.get("race_name", "")
        post_data = response.meta.get("post_data", {})
        try:
            self.logger.info(f"开始查找{race_no}的road_id:{response.url}")
            road_id = ""
            roads = json.loads(response.text).get("cmpt", {}).get("roads", [])
            for road in roads:
                if road.get("enable", True):
                    road_id = road.get("id", "")
                    race_group = road.get("name", "")
                    break
            if road_id:
                post_data.update({"roadId": str(road_id), "isSingleRank": "0", "queryType": "1111", "markNo": ""})
                yield FormRequest(url=self.rank_url, callback=self.parse_rank, formdata=post_data, dont_filter=True,
                                  errback=self.err_parse, headers=self.header,
                                  meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name,
                                        "race_group": race_group, "post_data": post_data})
        except Exception:
            self.logger.info(f"查找{race_no}的road_id时出错{response.url}：{traceback.format_exc()}")

    def parse_rank(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        race_name = response.meta.get("race_name", "")
        race_group = response.meta.get("race_group", "")
        post_data = response.meta.get("post_data", {})
        try:
            self.logger.info(f"开始查找{race_no}的rank_id:{response.url}")
            rank_id = ""
            ranks = json.loads(response.text).get("rankings", [])
            for rank in ranks:
                if rank.get("enable", True) and rank.get("userVisible", "1"):
                    rank_id = rank.get("id", "")
                    break
            if rank_id:
                cmpt_id = post_data.pop("cmptId", "")
                post_data.pop("roadId", "")
                post_data.pop("markNo", "")
                post_data.update({"rankId": str(rank_id)})
                yield FormRequest(url=self.base_score_url, callback=self.parse_base_score, formdata=post_data, dont_filter=True, errback=self.err_parse, headers=self.header,
                                  meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name, "race_group": race_group, "post_data": post_data, "cmpt_id": cmpt_id})
        except Exception:
            self.logger.info(f"查找{race_no}的rank_id时出错{response.url}：{traceback.format_exc()}")

    def parse_base_score(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        race_name = response.meta.get("race_name", "")
        race_group = response.meta.get("race_group", "")
        cmpt_id = response.meta.get("cmpt_id", "")
        post_data = response.meta.get("post_data", {})
        try:
            self.logger.info(f"开始解析{race_no}的基本成绩:{response.url}")
            data_list = json.loads(response.text).get("list", [])
            if data_list:
                for data in data_list:
                    r_no = data.get("mark", "")
                    if r_no == race_no:
                        _id = data.get("id", "")
                        index = data.get("index", "")
                        name = data.get("name", "")
                        length = data.get("length", "")
                        score_state = data.get("scoreState", "")
                        if data.get("realTime", 0):
                            time_str = data.get("realTime", 0)
                        else:
                            time_str = data.get("time", 0)
                        score = self.get_score(time_str)
                        score_data = {"race_name": race_name, "itemName": race_group, "index": index, "name": name, "raceNo": r_no,
                                      "distance": length, "score_status": score_state, "score": score}
                        post_data.pop("keyword", "")
                        post_data.pop("isSingleRank", "")
                        post_data.pop("queryType", "")
                        post_data.update({"type": "2", "id": _id, "cmptId": cmpt_id})
                        yield FormRequest(url=self.detail_url, callback=self.parse_detail_score, formdata=post_data,
                                          dont_filter=True, errback=self.err_parse, headers=self.header,
                                          meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name,
                                                "race_group": race_group, "score_data": score_data, "post_data": post_data})
        except Exception:
            self.logger.info(f"查找{race_no}的基本成绩时出错{response.url}：{traceback.format_exc()}")

    def parse_detail_score(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        race_name = response.meta.get("race_name", "")
        race_group = response.meta.get("race_group", "")
        score_data = response.meta.get("score_data", {})
        post_data = response.meta.get("post_data", {})
        try:
            self.logger.info(f"开始查找{race_no}的分段成绩:{response.url}")
            score_info = []
            data_list = json.loads(response.text).get("memberList", [])[0].get("segs", [])[0].get("cps", [])
            for data in data_list:
                cp_name = data.get("cpName", "")
                start_time = data.get("cpStartTime", "") if "." not in data.get("cpStartTime", "") else self.round_time(data.get("cpStartTime", ""))
                stop_time = data.get("cpStopTime", "") if "." not in data.get("cpStopTime", "") else self.round_time(data.get("cpStopTime", ""))
                cp_length = f'{int(data.get("cpLength", 0)) / 1000:.2f}'
                speed = data.get("speed", "")
                score_info.append({"cp_name": cp_name, "start_time": start_time, "score": stop_time, "distance": cp_length, "pace": speed})
            if score_info:
                score_info[-1]["cp_name"] = "FINISH"
            score_data["sectionScore"] = score_info
            post_data.pop("type", "")
            yield FormRequest(url=self.extend_url, callback=self.parse_extend_score, formdata=post_data,
                              dont_filter=True, errback=self.err_parse, headers=self.header,
                              meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name,
                                    "race_group": race_group, "score_data": score_data, "post_data": post_data})
        except Exception:
            self.logger.info(f"查找{race_no}的分段成绩时出错{response.url}：{traceback.format_exc()}")

    def parse_extend_score(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        race_name = response.meta.get("race_name", "")
        race_group = response.meta.get("race_group", "")
        score_data = response.meta.get("score_data", {})
        post_data = response.meta.get("post_data", {})
        try:
            self.logger.info(f"开始查找{race_no}的扩展成绩:{response.url}")
            data = json.loads(response.text)
            average_speed = data.get("averageSpeed", "")
            fast_speed = data.get("fastSpeed", "")
            slow_speed = data.get("slowSpeed", "")
            score_data.update({"fastPace": fast_speed, "slowPace": slow_speed, "pace": average_speed})
            if score_data.get("score") in ["", "00:00:00"]:
                result = self.result_item_assembler(response)
                result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                         "crawlerType": self.name_second, "data": str(score_data)}
                yield result
            else:
                cert_url = f"https://cert.geexek.com/getCertificatesURL?cmptId={post_data.get('cmptId', '')}&keyword={race_no}"
                if post_data.get('cmptId', '') in ["30136", "30045", "29946", "30089", "30188", "30322", "30317", "30239"]:
                    cert_url = f"https://timerbackend.geexek.com/getCertificatesURL.do?certType=0&cmptId={post_data.get('cmptId', '')}&enrollId={post_data.get('id', '')}"
                yield Request(url=cert_url, callback=self.parse_pic, errback=self.err_parse, dont_filter=True,
                              meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name,
                                    "race_group": race_group, "score_data": score_data})
        except Exception:
            self.logger.info(f"查找{race_no}的扩展成绩时出错{response.url}：{traceback.format_exc()}")

    def parse_pic(self, response):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        score_data = response.meta.get("score_data", {})
        try:
            self.logger.info(f"开始下载{race_no}的证书：{response.url}")
            pic_md5 = calc_str_md5(base64.b64encode(response.body).decode('utf-8'))
            if pic_md5 == "4381d73c18ac61ec233ea263685e5883":
                result = self.result_item_assembler(response)
                result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                         "crawlerType": self.name_second, "data": str(score_data)}
                yield result
            else:
                pic_name = f"{race_no}_{pic_md5}.jpg"
                dir_path = os.path.join(file_path, "picture", self.name_first)
                if not os.path.exists(dir_path):
                    os.makedirs(dir_path)
                save_path = os.path.join(dir_path, pic_name)
                if not os.path.exists(save_path):
                    with open(save_path, "wb") as f:
                        f.write(response.body)
                    upload_path = f"flow/{race_id}/{user_id}/pic/{pic_name}"
                    upload_flag = upload_file(save_path, upload_path)
                    if upload_flag:
                        self.logger.info(f"{save_path}上传成功：{upload_path}")
                    else:
                        self.logger.info(f"{save_path}上传失败：{upload_path}")
                    score_data["certImg"] = upload_path
                    result = self.result_item_assembler(response)
                    result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                             "crawlerType": self.name_second, "data": str(score_data)}
                    yield result
        except Exception:
            self.logger.info(f"下载{race_no}证书时出错{response.url}：{traceback.format_exc()}")

    def get_score(self, time_str):
        try:
            hour = str(int(time_str / 3600 / 1000)).zfill(2)
            minute = str(int(time_str / 1000 % 3600 / 60)).zfill(2)
            seconds = str(round(time_str / 1000.0 % 3600 % 60 + 0.5)).zfill(2)
            return f"{hour}:{minute}:{seconds}"
        except Exception:
            self.logger.info(f"处理赛事成绩时出错:{traceback.format_exc()}")

    def round_time(self, time_str):
        time_format = "%H:%M:%S.%f"
        dt = datetime.strptime(time_str, time_format)
        rounded = dt + timedelta(seconds=0.5)
        return rounded.strftime("%H:%M:%S")

    def err_parse(self, failure):
        self.logger.warning(f"请求失败：{failure.request.url},错误原因:{traceback.format_exc()}")

